/*  
 * 极简AES64加解密算法 （密钥字典加解密）
 * Version 1.1 Copyright (C) Qiepro kidming 2022-5-26.  
 * 
 * 64位显示字符加密，显示效果非常好。带打乱字符串顺序
 * 兼容AES,
 */

//默认Key
var _default_key = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789#'
//源编码
var _un_unicode = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz%';
//强制转码
var _en_unicode = '*-._@+/='

module.exports = {
	//自动填充到64位key
	Fillkey: true,
	//解密
	Decrypt: function(crypt_str, aes_key = null, fill_key = this.Fillkey) {
		crypt_str = String(crypt_str);

		let max = _un_unicode.length; // 最大值
		let alen = 0; // 加密过后单字符长度
		//生成编码表
		if (aes_key == '' || fill_key) {
			aes_key = this.UnSort(this.Unique(aes_key + _default_key), crypt_str.length)
			alen = 1;
		} else {
			if (aes_key.length < 2) return '';
			while (max > 0) {
				max = Math.floor(max / (aes_key.length + 0.1)); //计算单字符加密后长度
				alen++
			}
			aes_key = this.UnSort(this.Unique(aes_key), crypt_str.length / alen)
		}

		let result = [];
		let code = 0;
		for (let i = 0; i < crypt_str.length; i++) {
			code += aes_key.indexOf(crypt_str.charAt(i)) * (aes_key.length ** ((alen - 1) - (i % alen)))
			if (i % alen === (alen - 1)) {
				code = code - (Math.floor(i / alen) * 2) % aes_key.length
				if (code < 0) code += aes_key.length
				result.push(_un_unicode.charAt(code))
				code = 0;
			}
		}
		result = result.join('');
		for (let i = 0; i < _en_unicode.length; i++) result = result.replace(new RegExp(`[%]${80+i}`, 'g'),
			_en_unicode.charAt(i));
		return unescape(result);
	},
	//加密
	Encrypt: function(source_str, aes_key = '', fill_key = this.Fillkey) {
		//编码处理原字符串
		source_str = escape(source_str);
		for(let i= 0; i<_en_unicode.length;i++)source_str = source_str.replace(new RegExp(`[${_en_unicode.charAt(i)}]`, 'g'), "%" + (80 + i))
		
		//生成编码表
		if (aes_key == '' || fill_key) {
			aes_key = this.UnSort(this.Unique(aes_key + _default_key), source_str.length)
		} else {
			if (aes_key.length < 2) return '';
			aes_key = this.UnSort(this.Unique(aes_key), source_str.length)
		}

		let max = _un_unicode.length; // 最大值
		let alen; // 加密过后单字符长度
		for (alen = 0; max > 0; alen++) max = Math.floor(max / (aes_key.length + 0.1)); //计算单字符加密后长度

		let result = '';
		for (let i = 0; i < source_str.length; i++) {
			let num = _un_unicode.indexOf(source_str.charAt(i)) + (i * 2) % aes_key
				.length // 字符编码，用fromCharCode解码；
			let arr = new Array(alen); // 单字符转换过后的数组
			for (let si = alen; si > 0; si--) {
				arr[si - 1] = aes_key.charAt(num % aes_key.length)
				num = Math.floor(num / aes_key.length);
			}
			result += arr.join('');
		}
		return result;
	},
	//打乱字符串排列顺序
	UnSort: function(key, len) {
		for (let i = 0; i < key.length; i++) len += key.charCodeAt(i);
		key_len = key.length
		len = len % key_len
		let nstr = new Array(key_len);
		for (let i = 0; i < key_len; i++) {
			if (nstr[(i * len) % key_len] == undefined) {
				nstr[(i * len) % key_len] = key.charAt(i);
			} else {
				nstr[(i * len) % key_len] += key.charAt(i);
			}
		}
		return nstr.reverse().join('')
	},
	//字符串去重
	Unique: function(str) {
		let arr = String(str).split('');
		return Array.from(new Set(arr)).join('');
	}
}
